Задан массив целых чисел. Найдите
подмассив с максимальным XOR.
Вход. Первая строка содержит размер массива n (n ≤ 105).
Вторая строка содержит n целых чисел a1, a2,
..., an (0 ≤ ai
≤ 1018).
Выход. Выведите такие l и r, для которых al xor al+1 xor ... xor ar принимает наибольшее
значение среди всех возможных подмассивов
[l .. r] (1 ≤ l ≤ r ≤ n). Дальше в этой же строке
выведите значение максимального XOR.
Пример
входа |
Пример
выхода |
7 2 8 12 4 9 2 3 |
4 6 15 |
РЕШЕНИЕ
бор
b0 = 0,
b1 = a1,
b2 = a1 xor a2,
...,
bn = a1 xor a2 xor … xor an
Числа b0, b1, b2, ..., bn будем последовательно заносить в бинарный бор. Пусть b0, b1, b2, ..., bi уже находятся в боре. Найдем такое число bk (k < i), что bk xor bi максимально. Учитывая что bk xor bi = ak+1 xor … xor ai, этой операцией мы
ищем подмассив с максимальным XOR, который
заканчивается в ai. Среди всех таких максимумов ищем наибольший,
который и является ответом.
Объявим бинарный бор trie,
сыновья вершин бора соответствуют битам 0 и 1. В переменной TrieSize храним
его размер.
#define MAX 100001
int trie[MAX * 60][2];
long long b[MAX], mx;
int num[MAX * 60],
TrieSize;
Функция Insert вставляет число x = b[pos] в бор.
void Insert(int pos)
{
int v = 0;
long long x = b[pos];
Вставка числа в бор начинается со старших битов.
for (int i = 62; i >= 0;
i--)
{
Переменная bit содержит i-ый бит числа x.
int bit = x & (1LL
<< i) ? 1 : 0;
Если пути по биту bit в боре нет, то создаем новую вершину.
if (trie[v][bit] == -1)
trie[v][bit] = TrieSize++;
Двигаемся по бору дальше.
v = trie[v][bit];
}
Вершина v – конечная для числа x = b[pos]. Сохраним в num[v] индекс pos в массиве b.
num[v] = pos;
}
Функция Find возвращает индекс pos массива b, для
которого x xor bpos максимально.
int Find(long long x)
{
int i, v = 0;
for (i = 62; i >= 0;
i--)
{
Двигаемся по бору по битам, реверсным к двоичному представлению числа x.
int bit = x & (1LL << i) ? 0 : 1; // reverese bit
Если движение по бору невозможно, двигаемся по другому биту.
if (trie[v][bit] == -1)
bit ^= 1;
v = trie[v][bit];
}
Возвращаем индекс pos массива b, соответствующий вершине бора v.
return num[v];
}
Основная часть программы. Читаем входные данные. Изначально бор содержит
одну вершину (TrieSize = 1). Инициализируем массивы trie и num.
scanf("%d", &n);
TrieSize = 1;
memset(trie, -1, sizeof(trie));
memset(num, -1, sizeof(num));
Вставим в бор b0 = 0. В переменной mx вычисляем максимальное значение XOR на
подмассиве.
b[0] = 0;
Insert(0);
mx = 0;
Вставляем остальные числа последовательности b1, b2,
..., bn в бор.
for (i = 1; i <= n; i++)
{
Читаем значение ai = val.
scanf("%lld", &val);
Вычисляем bi = bi-1 xor ai.
b[i] = b[i - 1] ^ val;
Вставляем значение bi в бор.
Insert(i);
Находим такое k, что bk xor bi максимально.
Подмассив с максимальным XOR, который заканчивается в позиции i, начинается в k + 1. Отметим, что bk xor bi = ak+1 xor … xor ai.
k = Find(b[i]);
Среди всех значений ak+1
xor … xor ai (i = 1, 2, …, n) находим
наибольшее.
if ((b[k] ^ b[i]) > mx)
{
mx = b[k] ^ b[i];
l = k + 1;
r = i;
}
}
Выводим границы l и r искомого подмассива и значение XOR на нем.
printf("%d %d %lld\n", l, r, mx);